﻿using System;

using BizElements.Core;
using PostSharp.Aspects;

namespace BizElements.BusinessLayer.Aspects
{
    /// <summary>
    /// Used by <see cref="CachedAttribute"/> to generate global cache category for cached item equal to <b>IDbTable.TableName</b>.
    /// </summary>
    /// <remarks>Suitable for projects which use <b>BizElements</b> generated code. Tries to extract <b>IDbTable.TableName</b>
    /// for objects which implement <b>IEntity</b> interface or contain a <b>Table</b> property. If table cannot be extracted,
    /// the <see cref="CacheCategoryGenerator.DefaultCategory"/> value is used.</remarks>
    [Serializable]
    public sealed class CacheCategoryGenerator : ICacheCategoryGenerator
    {
        /// <summary>
        /// Gets default category used when table name cannot be determined.
        /// </summary>
        public static readonly string DefaultCategory = "BizElements.BusinessLayer.Aspects.CacheCategoryGenerator.DefaultCategory";

        /// <summary>
        /// Gets global cache categories for the method's return value.
        /// </summary>
        /// <param name="postsharpEventArgs">Arguments of events bound to an instance (because they relate to a field or to a method, for instance).</param>
        /// <returns>Array of categories assgined to the cache item.</returns>
        public string[] GetCategories(AdviceArgs postsharpEventArgs)
        {
            string category = GetCategory(postsharpEventArgs);
            return new string[] { category };
        }

        private string GetCategory(AdviceArgs postsharpEventArgs)
        {
            if (postsharpEventArgs.Instance == null)
                return DefaultCategory;

            IEntity entity = postsharpEventArgs.Instance as IEntity;
            if (entity != null)
                return entity.Table.TableName;

            string tableName = AopUtil.GetTableName(postsharpEventArgs);
            if (tableName != null)
                return tableName;

            return DefaultCategory;
        }
    }
}